﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;  //usado para administrar los hilos
using System.Collections;  //usado para ArrayList
using SistemaCenterQuimPost.Entidad;  //Usado para instanciar objetos de clase Producto y agilizar el filtrado de descripción.
using System.Text.RegularExpressions; //usado para expresiones regulares. Filtrar descripciones
using SistemaCenterQuimPost.Control; //usado para validar datos.
using SistemaCenterQuimPost.Plantillas; //necesario para obtener fecha, nombre usuario etc,

namespace SistemaCenterQuimPost.UI.PostAdministrador
{
    public partial class frmGestionProductosA : SistemaCenterQuimPost.UI.frmGestionProductos
    {
        //-------------------ATRIBUTOS--------------------------------------------------------
        
        
        //todos los metodos del padre, que usen resgProductoActual, deben ser obligadamente redefinido, ya que no procesarán sobre los mismos objetos.
        new private string[] resgProductoActual; //al ser una interface polifuncional. Guarda el producto encontrado en una busqueda exitosa. {codigoBarra, descripcion, precioCosto, precioVenta, stockActual, cantMinima, tipo, baseDesc, Porcentaje, ltrsXenvase}   

        private string[] resgBaseActual; //usado cuando se elige una base. {BaseCodigo, BaseDescripcion}

        protected Thread oHiloFiltrarBase; 
        
        //-----------------CONSTRUCTOR--------------------------------------------------------
        
        public frmGestionProductosA()
        {
            InitializeComponent();

            this.resgProductoActual = new String[10];  //inicializamos el resgProductoActual 
            this.resgBaseActual = new String[2]; //inicializamos el resgBaseActual
            this.oHiloFiltrarBase = new Thread(new ThreadStart(filtrarBase)); //inicializamos el hilo para filtrar base.

        }


        //-----------------ESTADOS-------------------------------------------------------------
        
        private void frmGestionProductosA_Load(object sender, EventArgs e)
        {
            rbtnBase.Checked = true; //seteamos el cbo cuando inicia el form
        }

        
        //redefine método del padre.
        protected override void estEsperandoOperacion() //estado luego de realizar una busqueda exitosa, agregar o editar. Es decir con datos en vista.
        {

            estadoDelFormulario = "estEsperandoOperacion";

            txtPrecioCosto.UseSystemPasswordChar = false; //Se coloca el pasword a falso. En el estado agregar puede ver el costo del producto.
            txtPrecioCosto.PasswordChar = '\0';
            
            if (this.txtPrecioVenta.Text == "") //estado al iniciar el formulario
            {
                System.Windows.Forms.Control[] controlesHabilitados = { this.txtCodBarra, this.btnBusCodigo, this.txtDescripcion, this.btnBusDescripcion, this.btnAgregar};
                System.Windows.Forms.Control[] controlesDeshabilitados = {this.txtPrecioCosto, this.txtPrecioVenta, this.txtStockActual, this.txtCantMinima, this.btnEditar, this.btnEliminar, this.btnProcesar, this.gbTipo, this.txtBase, this.txtPorcentaje, this.txtLtrsEnvase };
                System.Windows.Forms.Control[] controlesVisibles = {};
                System.Windows.Forms.Control[] controlesInvisibles = {this.lstProductosCodBarra, this.lstProductosDescripcion,lstProductosBases, lblErrorDescripcion, lblErrorPCosto, lblErrorPVenta, lblErrorStockActual, lblErrorCantMin, lblErrorPorcentaje, lblErrorLtrsEnv, lblError};

                habilitarControles(controlesHabilitados);
                deshabilitarControles(controlesDeshabilitados);
                visibleControles(controlesVisibles);
                invisibleControles(controlesInvisibles);

                if (refrescarResgProductos) //si hace falta actualizar el refrescarResgProducto se realiza
                {
                    ejecutarHiloActualizarResgProductos();

                }

            }
            else   //estado luego de una busqueda.
            {
                System.Windows.Forms.Control[] controlesHabilitados = { this.txtCodBarra, this.btnBusCodigo, this.txtDescripcion, this.btnBusDescripcion, this.btnAgregar, this.btnEditar, this.btnEliminar };
                System.Windows.Forms.Control[] controlesDeshabilitados = { this.txtPrecioCosto, this.txtPrecioVenta, this.txtStockActual, this.txtCantMinima, this.btnProcesar, this.gbTipo, this.txtBase, this.txtPorcentaje, this.txtLtrsEnvase };
                System.Windows.Forms.Control[] controlesVisibles = { };
                System.Windows.Forms.Control[] controlesInvisibles = { this.lstProductosCodBarra, this.lstProductosDescripcion, lstProductosBases, lblErrorDescripcion, lblErrorPCosto, lblErrorPVenta, lblErrorStockActual, lblErrorCantMin, lblErrorPorcentaje, lblErrorLtrsEnv, lblError };

                habilitarControles(controlesHabilitados);
                deshabilitarControles(controlesDeshabilitados);
                visibleControles(controlesVisibles);
                invisibleControles(controlesInvisibles);

            }

            errorProvider1.Clear();  //se borran los errores, si habian.

            txtCodBarra.Focus();   //se deja el foco en txtCodBarra

        }


        //redefine método del padre
        protected override void estAgregar() 
        {
            estadoDelFormulario = "estAgregar";
            
            txtPrecioCosto.UseSystemPasswordChar = false; //Se coloca el pasword a falso. En el estado agregar puede ver el costo del producto.
            txtPrecioCosto.PasswordChar = '\0';
            

            if (!(rbtnDisueltos.Checked)) //Si no es un producto disuelto es decir es un producto terminado o base.
            {
                System.Windows.Forms.Control[] controlesHabilitados = { this.txtCodBarra, this.txtDescripcion, this.txtPrecioCosto, this.txtPrecioVenta, this.txtStockActual, this.txtCantMinima, this.btnAgregar, this.btnProcesar, this.gbTipo};
                System.Windows.Forms.Control[] controlesDeshabilitados = { this.btnBusCodigo, this.btnBusDescripcion, this.btnEditar, this.btnEliminar, this.txtBase, this.txtPorcentaje, this.txtLtrsEnvase };
                System.Windows.Forms.Control[] controlesVisibles = { lblErrorDescripcion, lblErrorPCosto, lblErrorPVenta, lblErrorStockActual, lblErrorCantMin};
                System.Windows.Forms.Control[] controlesInvisibles = { this.lstProductosCodBarra, this.lstProductosDescripcion, this.lstProductosBases, lblErrorPorcentaje, lblErrorLtrsEnv, lblError };

                habilitarControles(controlesHabilitados);
                deshabilitarControles(controlesDeshabilitados);
                visibleControles(controlesVisibles);
                invisibleControles(controlesInvisibles);

            }
            else
            {
                System.Windows.Forms.Control[] controlesHabilitados = { this.txtCodBarra, this.txtDescripcion, this.txtPrecioCosto, this.txtPrecioVenta, this.txtStockActual, this.txtCantMinima, this.btnAgregar, this.btnProcesar, this.gbTipo, this.txtBase, this.txtPorcentaje, this.txtLtrsEnvase };
                System.Windows.Forms.Control[] controlesDeshabilitados = { this.btnBusCodigo, this.btnBusDescripcion, this.btnEditar, this.btnEliminar };
                System.Windows.Forms.Control[] controlesVisibles = { lblErrorDescripcion, lblErrorPCosto, lblErrorPVenta, lblErrorStockActual, lblErrorCantMin, lblErrorPorcentaje, lblErrorLtrsEnv };
                System.Windows.Forms.Control[] controlesInvisibles = { this.lstProductosCodBarra, this.lstProductosDescripcion, this.lstProductosBases, lblError };

                habilitarControles(controlesHabilitados);
                deshabilitarControles(controlesDeshabilitados);
                visibleControles(controlesVisibles);
                invisibleControles(controlesInvisibles);
            }

            errorProvider1.Clear();

            txtCodBarra.Focus();

        }

        private string obtenerFechaActual()  //Dato necesario para el alta de venta
        {
            frmPlantillaPadre unFrm = (frmPlantillaPadre)this.MdiParent;
            return unFrm.getFechaActual();
        }

        //redefine método del padre
        protected override void estEditar()
        {
            txtPrecioCosto.UseSystemPasswordChar = false; //Se coloca el pasword a falso. En el estado agregar puede ver el costo del producto.
            txtPrecioCosto.PasswordChar = '\0';
            
            
            if (!esDisuelto()) //Si no es un producto disuelto es decir es un producto terminado o base.
            {
                System.Windows.Forms.Control[] controlesHabilitados = {this.txtPrecioCosto, this.txtPrecioVenta, this.txtCantMinima, this.btnEditar, this.btnProcesar};
                System.Windows.Forms.Control[] controlesDeshabilitados = { this.txtCodBarra, this.btnBusCodigo, this.txtDescripcion ,this.btnBusDescripcion, this.txtStockActual, this.btnAgregar, btnEliminar, this.gbTipo, this.txtBase, this.txtPorcentaje, this.txtLtrsEnvase };
                System.Windows.Forms.Control[] controlesVisibles = { lblErrorPCosto, lblErrorPVenta, lblErrorCantMin};
                System.Windows.Forms.Control[] controlesInvisibles = {this.lstProductosCodBarra, lstProductosDescripcion, lstProductosBases, lblErrorDescripcion,lblErrorStockActual, lblErrorPorcentaje, lblErrorLtrsEnv, lblError };

                habilitarControles(controlesHabilitados);
                deshabilitarControles(controlesDeshabilitados);
                visibleControles(controlesVisibles);
                invisibleControles(controlesInvisibles);

            }
            else
            {
                System.Windows.Forms.Control[] controlesHabilitados = {this.txtPrecioCosto, this.txtPrecioVenta, this.txtCantMinima, this.btnEditar, this.btnProcesar, txtPorcentaje, txtLtrsEnvase};
                System.Windows.Forms.Control[] controlesDeshabilitados = { this.txtCodBarra, this.btnBusCodigo, this.txtDescripcion,this.btnBusDescripcion, this.txtStockActual, this.btnAgregar, btnEliminar, gbTipo,txtBase };
                System.Windows.Forms.Control[] controlesVisibles = { lblErrorPCosto, lblErrorPVenta, lblErrorCantMin, lblErrorPorcentaje, lblErrorLtrsEnv};
                System.Windows.Forms.Control[] controlesInvisibles = { this.lstProductosCodBarra, lstProductosDescripcion, lstProductosBases, lblErrorDescripcion, lblErrorStockActual, lblError };

                habilitarControles(controlesHabilitados);
                deshabilitarControles(controlesDeshabilitados);
                visibleControles(controlesVisibles);
                invisibleControles(controlesInvisibles);
            }

            errorProvider1.Clear();

            txtCodBarra.Focus();

            estadoDelFormulario = "estEditar";

            
        }
        
        private bool esDisuelto() //verificar que sea un producto disuelto. Usado cuando se va a editar.
        {
            return (resgProductoActual[6] == "D");
        }

        
        //redefine método del padre
        protected override void vaciarTextBox() //Se deja en blanco todos los textBox, usado en estados estInicial y estAgregar; tambien luego de eliminar.
        {
            base.vaciarTextBox(); //lama a la clase padre que tiene parte del método

            this.txtBase.Text = "";
            this.txtPorcentaje.Text = "";
            this.txtLtrsEnvase.Text = "";

        }

        //redefine método del padre
        protected override void resguardarProductoActual() //Guarda los valores de los textBox en array resgProductoActual, luego de una busqueda exitosa.
        {
            //No se puede llamar al método del padre, porque utiliza diferente atributo para resguardar. Debo implementarlo completamente.
            
            this.resgProductoActual[0] = txtCodBarra.Text;
            this.resgProductoActual[1] = txtDescripcion.Text;
            this.resgProductoActual[2] = txtPrecioCosto.Text;
            this.resgProductoActual[3] = txtPrecioVenta.Text;
            this.resgProductoActual[4] = txtStockActual.Text;
            this.resgProductoActual[5] = txtCantMinima.Text;

            
            string tipo = "";              //se verifica de que tipo es el producto.

            if (rbtnBase.Checked)
            {
                tipo = "B";
            }else
            {
                if (rbtnTerminados.Checked)
                {
                    tipo = "T";
                }
                else
                {
                    tipo = "D";
                }
            }
            this.resgProductoActual[6] = tipo;
            this.resgProductoActual[7] = txtBase.Text;
            this.resgProductoActual[8] = txtPorcentaje.Text;
            this.resgProductoActual[9] = txtLtrsEnvase.Text;
 
        }


        //redefine método del padre
        protected override void deshacerCambios()  //usado cuando en estado editar o agregar, se arrepiente (no se apreta en procesar) y se vuelve a estado esperandoOperacion.
        {
            txtCodBarra.Text = this.resgProductoActual[0];
            txtDescripcion.Text = this.resgProductoActual[1];
            txtPrecioCosto.Text = this.resgProductoActual[2];
            txtPrecioVenta.Text = this.resgProductoActual[3];
            txtStockActual.Text = this.resgProductoActual[4];
            txtCantMinima.Text = this.resgProductoActual[5];

            if (resgProductoActual[6] == "B")
            {
                rbtnBase.Checked = true;
            } else
            {
                if (resgProductoActual[6] == "T")
                {
                    rbtnTerminados.Checked = true;
                } else
                {
                    rbtnDisueltos.Checked = true;
                }
            }

            txtBase.Text = resgProductoActual[7];
            txtPorcentaje.Text = resgProductoActual[8];
            txtLtrsEnvase.Text = resgProductoActual[9];

        }


        //redefine método del padre
        protected override void cargarProductoPorCodigo(string unCodBarra) //busca producto con codigo de barra único (una coincidencia) encontrado en el oHiloFiltrarCodBarra y lo carga en los textBox.
        {
            try
            {
                //(ALE)HACER EL FILL O COMO LO LLAMES ACA ABAJO
                //ProductosTa.FillByProductos1(centerQuimDs,unCodBarra);
                productosTa.FillByCodigo(centerQuimDs.Productos, unCodBarra);

                //ARREGLAR ESTO. Se rellena los textBox con la consulta encontrada. 
                txtCodBarra.Text = centerQuimDs.Productos[0].codProducto;
                txtDescripcion.Text = centerQuimDs.Productos[0].descripcion;
                txtPrecioCosto.Text = centerQuimDs.Productos[0].precioCosto.ToString();
                txtPrecioVenta.Text = centerQuimDs.Productos[0].precioVenta.ToString();
                txtCantMinima.Text = centerQuimDs.Productos[0].cantidadMinima.ToString();
                txtStockActual.Text = centerQuimDs.Productos[0].stockActual.ToString();
                
                if (centerQuimDs.Productos[0].tipo.ToString() == "B")              //setea el radio buton correspondiente.
                {
                    rbtnBase.Checked = true;
                }else
                {
                    if (centerQuimDs.Productos[0].tipo.ToString() == "T")
                    {
                        rbtnTerminados.Checked = true;
                    }else
                    {
                        rbtnDisueltos.Checked = true;
                    }
                }

                txtBase.Text = centerQuimDs.Productos[0].baseDescripcion;
                txtPorcentaje.Text = centerQuimDs.Productos[0].porcentaje.ToString();
                txtLtrsEnvase.Text = centerQuimDs.Productos[0].litrosEnvase.ToString();


            }
            catch (IndexOutOfRangeException)
            {

            }
            catch (Exception ex)
            {
                //Por cualquier otra excepcion se informa el error, en este caso es un error grave.
                MessageBox.Show("La conexión a la base de datos no fué exitosa.\n\n Comuniquese con su desarrollador para solucionar el problema.\n\n" + ex.Message, "ERROR GRAVE - ACCESO A BASE DE DATO", MessageBoxButtons.OK, MessageBoxIcon.Error);

                //Si llega a ocurrir algún error grave se cierra el formulario 
                this.Close();
            }
        }

        //redefine método del padre
        protected override void cargarProductoPorDescripcion(string unaDescripcion)  //busca el producto por descripción en la base de datos y lo carga en los textbox.
        {
            //(ALE) HACER EL FILL O COMO LO LLAMES ACA ABAJO
            productosTa.FillByNombre(centerQuimDs.Productos, unaDescripcion);

            //ARREGLAR ESTO. Se rellena los textBox con la consulta encontrada. 
            txtCodBarra.Text = centerQuimDs.Productos[0].codProducto;
            txtDescripcion.Text = centerQuimDs.Productos[0].descripcion;
            txtPrecioCosto.Text = centerQuimDs.Productos[0].precioCosto.ToString();
            txtPrecioVenta.Text = centerQuimDs.Productos[0].precioVenta.ToString();
            txtCantMinima.Text = centerQuimDs.Productos[0].cantidadMinima.ToString();
            txtStockActual.Text = centerQuimDs.Productos[0].stockActual.ToString();

            if (centerQuimDs.Productos[0].tipo.ToString() == "B")              //setea el radio buton correspondiente.
            {
                rbtnBase.Checked = true;
            }
            else
            {
                if (centerQuimDs.Productos[0].tipo.ToString() == "T")
                {
                    rbtnTerminados.Checked = true;
                }
                else
                {
                    rbtnDisueltos.Checked = true;
                }
            }

            txtBase.Text = centerQuimDs.Productos[0].baseDescripcion;
            txtPorcentaje.Text = centerQuimDs.Productos[0].porcentaje.ToString();
            txtLtrsEnvase.Text = centerQuimDs.Productos[0].litrosEnvase.ToString();


        }

        //redefine método del padre
        protected override void btnEditar_Click(object sender, EventArgs e)
        {
            if (estadoDelFormulario == "estEsperandoOperacion")
            {
                deshacerCambios();  //vuelve a cargar el producto que se mostraba antes en la última busqueda exitosa

                txtDescripcion.Text = this.resgProductoActual[1].Substring(2, this.resgProductoActual[1].Length - 2);

                estEditar();  //deja en estado editar
            }
            else
            {
                deshacerCambios();  //vuelve a cargar el producto que se mostraba antes.

                estEsperandoOperacion();
            }
            
        }

        //redefine método del padre
        protected override void editarProducto()
        {
            DialogResult result = MessageBox.Show("¿Desea actualizar el siguiente producto? \nCodigo: " + resgProductoActual[0] + ", - Descripción: " + resgProductoActual[1], "CONFIRMACION EDICION DE PRODUCTO", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

            if (result == DialogResult.Yes)
            {

                //FIJATE SI ESTÁ TODO BIEN. QUE COINCIDA CON TU CONSULTA
                productosTa.FillByNombre(centerQuimDs.Productos, resgProductoActual[1]);  //el argumento corresponde con la descripcion actual del producto a editar.
                
                centerQuimDs.Productos[0].descripcion = resgProductoActual[1].Substring(0,2) + txtDescripcion.Text.Trim().ToUpper();
                centerQuimDs.Productos[0].precioCosto = Math.Round(Convert.ToDouble(txtPrecioCosto.Text.Trim()), 2);
                if (centerQuimDs.Productos[0].precioVenta != Math.Round(Convert.ToDouble(txtPrecioVenta.Text.Trim()), 2))
                {
                    centerQuimDs.Productos[0].fechaActualización = Convert.ToDateTime(obtenerFechaActual());
                }
                centerQuimDs.Productos[0].precioVenta = Math.Round(Convert.ToDouble(txtPrecioVenta.Text.Trim()), 2);
                centerQuimDs.Productos[0].cantidadMinima = Convert.ToDouble(txtCantMinima.Text.Trim());
                centerQuimDs.Productos[0].porcentaje = Convert.ToDouble(txtPorcentaje.Text);
                centerQuimDs.Productos[0].litrosEnvase = Convert.ToDouble(txtLtrsEnvase.Text);
                
                productosTa.Update(centerQuimDs.Productos);

                txtDescripcion.Text = resgProductoActual[1].Substring(0, 2) + txtDescripcion.Text.Trim().ToUpper(); //Se coloca el formato correcto para la descripción


                //Se muestra un mje de confirmación.
                MessageBox.Show("Producto editado con exito!!!", "AVISO", MessageBoxButtons.OK, MessageBoxIcon.Information);

                refrescarResgProductos = true;  //como se agregó un producto el resgProductos está desactualizado.

                resguardarProductoActual(); //Se resguarda el producto actual editado correctamente.

                estEsperandoOperacion(); //Luego de insertar un usuario se vuelve al estado esperando operación. Para que pueda editarlo o eliminarlo rapidamente.

            }
        }

        //redefine método del padre
        protected override void agregarProducto()
        {
            DialogResult result = MessageBox.Show("¿Está seguro en ingresar el nuevo producto?.", "CONFIRMACION INGRESO DE PRODUCTO", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

            if (result == DialogResult.Yes)
            {

                string tipo = "";              //se verifica de que tipo es el producto.

                if (rbtnBase.Checked)
                {
                    tipo = "B";
                }
                else
                {
                    if (rbtnTerminados.Checked)
                    {
                        tipo = "T";
                    }
                    else
                    {
                        tipo = "D";
                    }
                }

                if (tipo == "D")
                {
                    //(ALE)FIJATE SI ESTÁ TODO BIEN. QUE COINCIDA CON TU CONSULTA
                    productosTa.InsertQueryProducto(resgBaseActual[0], tipo + " " + txtDescripcion.Text.Trim().ToUpper(), Math.Round(Convert.ToDecimal(txtPrecioCosto.Text.Trim()), 2), Math.Round(Convert.ToDecimal(txtPrecioVenta.Text.Trim()), 2), Convert.ToDecimal(txtStockActual.Text.Trim()), Convert.ToDecimal(txtCantMinima.Text.Trim()), tipo, resgBaseActual[0], resgBaseActual[1], Convert.ToDecimal(txtLtrsEnvase.Text), Convert.ToDecimal(txtPorcentaje.Text), true, DateTime.Today);
                    
                }else
                {
                    //(ALE)FIJATE SI ESTÁ TODO BIEN. QUE COINCIDA CON TU CONSULTA
                    productosTa.InsertQueryProducto(txtCodBarra.Text.Trim(),  tipo + " " + txtDescripcion.Text.Trim().ToUpper(), Math.Round(Convert.ToDecimal(txtPrecioCosto.Text.Trim()), 2), Math.Round(Convert.ToDecimal(txtPrecioVenta.Text.Trim()), 2), Convert.ToDecimal(txtStockActual.Text.Trim()), Convert.ToDecimal(txtCantMinima.Text.Trim()), tipo, "", "", 0, 0, true, DateTime.Today);
                   
                }
                
                //Se muestra un mje de confirmación.
                MessageBox.Show("Producto ingresado con exito!!!", "AVISO", MessageBoxButtons.OK, MessageBoxIcon.Information);

                refrescarResgProductos = true;  //como se agregó un producto el resgProductos está desactualizado.

                darFormatoADatos(tipo); //Arregla los valores pasando a mayuscula, dejando como quedó en la base de datos.
                
                resguardarProductoActual(); //Se resguarda el producto actual insertado correctamente.

                estEsperandoOperacion(); //Luego de insertar un usuario se vuelve al estado esperando operación. Para que pueda editarlo o eliminarlo rapidamente.
            }

        }

        private void darFormatoADatos(string unTipo)
        {
            txtDescripcion.Text = unTipo + " " + txtDescripcion.Text.Trim().ToUpper();
            txtPrecioCosto.Text = Math.Round(Convert.ToDecimal(txtPrecioCosto.Text.Trim()), 2).ToString();
            txtPrecioVenta.Text = Math.Round(Convert.ToDecimal(txtPrecioVenta.Text.Trim()), 2).ToString();
            txtStockActual.Text = Convert.ToDecimal(txtStockActual.Text.Trim()).ToString();
            txtCantMinima.Text = Convert.ToDecimal(txtCantMinima.Text.Trim()).ToString();

            if (unTipo == "D")
            {
                txtLtrsEnvase.Text = Convert.ToDecimal(txtLtrsEnvase.Text).ToString();
                txtPorcentaje.Text = Convert.ToDecimal(txtPorcentaje.Text).ToString();
                txtCodBarra.Text = resgBaseActual[0];

            } else
            {
                txtCodBarra.Text = txtCodBarra.Text.Trim();
            }

        }
        
        //redefine método del padre
        protected override bool formularioValido()
        {
            if (estadoDelFormulario == "estAgregar")
            {
                base.validarCodBarra();

                validarDescripcion();

                base.validarPrecioCosto();

                base.validarPrecioVenta();


                //Validacion de Stock Actual y cantidad Minima en agregar
                if (rbtnTerminados.Checked)            //si es un producto terminado. El stockActual y CantMinima deben ser naturales.
                {
                    base.validarStockActual();

                    base.validarCantMinima();

                }
                else
                {
                    if (rbtnBase.Checked)            //si es un producto base. El stockActual y CantMinima deben ser reales positivos con cero.
                    {
                        this.validarStockActual();

                        this.validarCantMinima();
                    }
                    else
                    {
                        
                        
                        this.validarBase();  //valida si el txtBase no está vacio.

                        this.validarPorcentaje();

                        
                        if ((txtLtrsEnvase.Text == "") || (txtLtrsEnvase.Text == "0"))   //Si el ltrsEnvase es blanco o cero, es un producto Disuelto por Granel.
                        {
                            txtLtrsEnvase.Text = "0";
                            
                            this.validarStockActual();    //el stock actual y la cantidad mínima deben ser reales positivos con cero

                            this.validarCantMinima();
                            
                        } else                          //Es un producto disuelto para vender por cantidad.
                        
                        {
                            base.validarStockActual();    //el stock actual y la cantidad mínima deben ser reales positivos con cero

                            base.validarCantMinima();

                            validarLtrsEnvase();
                        }

                    }
                }

            } else // se encuentra en estado Editar
            {
                validarDescripcion();

                base.validarPrecioCosto();

                base.validarPrecioVenta();

                //Cantidad Minima en edicion
                if (rbtnTerminados.Checked)            //si es un producto terminado. CantMinima deben ser natural
                {
                    
                    base.validarCantMinima();

                }
                else
                {
                    if (rbtnBase.Checked)            //si es un producto base. CantMinima debe ser real positivo con cero.
                    {
                        
                        this.validarCantMinima();
                    }
                    else
                    {

                        this.validarPorcentaje();


                        if ((txtLtrsEnvase.Text == "") || (txtLtrsEnvase.Text == "0"))   //Si el ltrsEnvase es blanco o cero, es un producto Disuelto por Granel.
                        {
                            txtLtrsEnvase.Text = "0";

                            this.validarCantMinima();    //La cantidad mínima deben ser real positivo con cero

                        }
                        else                          //Es un producto disuelto para vender por cantidad.
                        {
                            base.validarCantMinima();    //La cantidad mínima deben ser real positivo con cero

                            validarLtrsEnvase();
                        }
                    }
                }
            }
    
            if ((errorProvider1.GetError(txtCodBarra) == "") && (errorProvider1.GetError(txtDescripcion) == "") && (errorProvider1.GetError(txtPrecioCosto) == "") && (errorProvider1.GetError(txtPrecioVenta) == "") && (errorProvider1.GetError(txtStockActual) == "") && (errorProvider1.GetError(txtCantMinima) == "") && (errorProvider1.GetError(txtPorcentaje) == "") && (errorProvider1.GetError(txtLtrsEnvase) == "") && (errorProvider1.GetError(txtBase) == ""))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        
        private void txtBase_TextChanged(object sender, EventArgs e)
        {
            if (this.estadoDelFormulario == "estAgregar")
            {
                eventoBusBase();
            }
        }

        private void eventoBusBase()
        {
            if (txtBase.Text != "") //Si txtBase es distinto de blanco se realiza el procesamiento. Esto se realiza para no perder el tiempo en filtro innecesarios.
            {
                if (refrescarResgProductos)   //si es necesario actualizar el resgProductos se lo hace sino no
                {
                    ejecutarHiloActualizarResgProductos();
                }

                ejecutarHiloFiltrarBase();

                if (lstProductosBases.Items.Count == 0)  //el filtro no obtuvo coincidencias, no se muestra el lstProductosBases
                {
                    lstProductosBases.Visible = false;
                    lstProductosBases.Enabled = false;

                }
                else
                {
                    lstProductosBases.Visible = true; //si se obtuvo una o más coincidencia se muestran en lstProductosBases, y espera a que el usuario seleccione una.
                    lstProductosBases.Enabled = true;

                }

            }
            else  //Si txtBase es blanco no se realiza el procesamiento
            {
                lstProductosBases.Enabled = false;
                lstProductosBases.Visible = false;
            }
        }

        private void ejecutarHiloFiltrarBase()
        {
            if ((this.oHiloFiltrarBase.ThreadState == ThreadState.Unstarted) || (this.oHiloFiltrarBase.ThreadState == ThreadState.Stopped))
            {
                this.oHiloFiltrarBase = new Thread(new ThreadStart(filtrarBase)); //Instancia el hilo y lo delega al metodo filtrarBase. 
                this.oHiloFiltrarBase.Priority = ThreadPriority.AboveNormal;
                this.oHiloFiltrarBase.Start();  //hilo que filtra las bases asociadas al valor del txtBase y lo carga en lstProductosBases
            }
        }

        private void filtrarBase()
        {
            lstProductosBases.Items.Clear(); //vaciamos el lstProductosBases por si tuviera descripciones anteriores.

            try
            {
                foreach (Producto unProducto in resgProductos) //buscamos las bases que coinciden con ("B" + blanco + txtDescripcion.text + ninguna o muchas palabras o letras) y la cargamos en el lstProductosBase
                {

                    if (Regex.Match(unProducto.Descripcion, "^B .*" + txtBase.Text.Trim().ToUpper() + ".*$").Success)
                    {
                        lstProductosBases.Items.Add(unProducto.Descripcion);
                    }

                }
            }
            catch (InvalidOperationException)
                    {

                    }

                    catch (Exception)
                    {
                        txtBase.Text = "";

                    }
            
        }

        private void lstProductosBases_DoubleClick(object sender, EventArgs e) //captura en evento doble click sobre lstProductosBase
        {
            procesarEleccionLstProductosBase();
        }

        
        private void procesarEleccionLstProductosBase() //se encapsulo para que se pueda usar con DoubleClick y Enter sobre el lstProductosBase
        {
            try
            {
                this.estadoDelFormulario = "Buscando";  //Se coloca este estado ya que si encuentra algo, cargará el txtDescripcion y lanzará el evento TextChanged()

                resguardarBaseActual(lstProductosBases.SelectedItem.ToString()); //Guarda los valores de los textBox luego de una busqueda exitosa.

                this.estadoDelFormulario = "estAgregar"; //se deja en el estado necesario

                txtPorcentaje.Focus(); //se deja el foco en el porcentaje.

            }
            catch (IndexOutOfRangeException)
            {

            }
            catch (Exception ex)
            {
                //Por cualquier otra excepcion se informa el error, en este caso es un error grave.
                MessageBox.Show("La conexión a la base de datos no fué exitosa.\n\n Comuniquese con su desarrollador para solucionar el problema.\n\n" + ex.Message, "ERROR GRAVE - ACCESO A BASE DE DATO", MessageBoxButtons.OK, MessageBoxIcon.Error);

                //Si llega a ocurrir algún error grave se cierra el formulario 
                this.Close();
            }
        }

        private void resguardarBaseActual(string unaBaseDescripcion)
        {
            //(ALE) HACER EL FILL O COMO LO LLAMES ACA ABAJO
            productosTa.FillByNombre(centerQuimDs.Productos, unaBaseDescripcion);

            //ARREGLAR ESTO. Se rellena los textBox con la consulta encontrada. 
            txtBase.Text = centerQuimDs.Productos[0].descripcion;

            resgBaseActual[0] = centerQuimDs.Productos[0].codProducto; //resguardamos la datos (codigo y descripcion) de la base seleccionada.
            resgBaseActual[1] = centerQuimDs.Productos[0].descripcion;
            
        }

        private void lstProductosBases_Leave(object sender, EventArgs e)
        {
            this.lstProductosBases.Visible = false;
        }

        private void txtBase_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.KeyCode == Keys.Down) & (lstProductosBases.Visible)) //Si se presiona para abajo y tiene a lstProductosBases visible (es decir se encuentra esperando operacion y con items en la lista)
            {
                lstProductosBases.SetSelected(0, true); //se deja seleccionado el primer items
                lstProductosBases.Focus(); //Se deja el foco sobre este control para que seleccione un items.
            }
            else
            {
                if ((e.KeyCode == Keys.Enter) & (this.estadoDelFormulario == "estAgregar"))  //Si se presiona Enter y esta en el estado esperando operación con elementos en lstProductosDescripcion
                {
                    eventoBusBase();
                }

            }
        }

        private void lstProductosBases_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                procesarEleccionLstProductosBase();
            }
            else
            {
                if ((e.KeyCode == Keys.Up) & (lstProductosBases.SelectedIndex == 0))//si llega al primer lugar y presiona para arriba, vuelve al txtCodBarra
                {
                    txtBase.Focus();
                }
            }
        }


        //redefine método del padre
        protected override void validarDescripcion()
        {
            if (txtDescripcion.Text.Trim() == "")
            {
                errorProvider1.SetError(txtDescripcion, "Descripcion: el campo se encuentra vacio\n\n");
            }
            else
            {
                if (this.estadoDelFormulario == "estAgregar")
                {
                    errorProvider1.SetError(txtDescripcion, new ValidarDatos().validarLongitud("Descripcion:", txtDescripcion.Text, 50) + validarDuplDescripcion(0));

                }
                else //estEditar
                {
                    if ((txtDescripcion.Text.Trim().ToUpper()) == (resgProductoActual[1].Substring(2,resgProductoActual[1].Length-2))) //Si se va a editar y no cambia la descripción. Puede haber una sola coincidencia (el mismo producto)
                    {
                        errorProvider1.SetError(txtDescripcion, new ValidarDatos().validarLongitud("Descripcion:", txtDescripcion.Text, 50) + validarDuplDescripcion(1));
                    }
                    else
                    {
                        errorProvider1.SetError(txtDescripcion, new ValidarDatos().validarLongitud("Descripcion:", txtDescripcion.Text, 50) + validarDuplDescripcion(0)); //Si se va a editar y cambia la descripción. No puede haber coincidencias con la descripcion.
                    }

                }

            }
        }

        //redefine método del padre
        protected override string validarDuplDescripcion(int maxCoincidencia) //valida que no existan otros productos con esta descripción. El argumento define el maximo de coincidencia que puede aceptarse.
        {
            int coincidencia = 0;

            foreach (Producto unProducto in resgProductos) //buscamos las descripciones que coinciden con (una T + un caracter blanco + txtDescripcion.text) y la cargamos en el lstProductosDescripcion
            {
                if (Regex.Match(unProducto.Descripcion, @"^(T|B|D)\s" + txtDescripcion.Text.Trim().ToUpper() + "$").Success)
                {
                    coincidencia++;
                }

            }

            if (coincidencia > maxCoincidencia)
            {
                return "Descripcion: ya existe otro producto con ésta descripción.";
            }
            else
            {
                return "";
            }

        }

        protected override void validarStockActual()  //el stock actual debe ser en este caso entero positivo con el cero. Ya que son productos terminados.
        {
            if (txtStockActual.Text.Trim() == "")
            {
                errorProvider1.SetError(txtStockActual, "Stock Actual: el campo se encuentra vacio\n\n");
            }
            else
            {
                errorProvider1.SetError(txtStockActual, new ValidarDatos().validarRealesPositvos("Stock Actual:", txtStockActual.Text));
            }
        }

        protected override void validarCantMinima() //la cant.Minima debe ser en este caso entero positivo con el cero. Ya que son productos terminados.
        {
            if (txtCantMinima.Text.Trim() == "")
            {
                errorProvider1.SetError(txtCantMinima, "Cantidad Mínima: el campo se encuentra vacio\n\n");
            }
            else
            {
                errorProvider1.SetError(txtCantMinima, new ValidarDatos().validarRealesPositvos("Cantidad Mínima:", txtCantMinima.Text));
            }
        }

        private void validarBase()  //debe asignarse una base si se agrega un producto disuelto.
        {
            if (txtBase.Text.Trim() == "")
            {
                errorProvider1.SetError(txtBase, "Base : el campo se encuentra vacio\n\n");
            }
            else
            {
                errorProvider1.SetError(txtBase,"");
            }
        }

        private void validarPorcentaje()
        {
            if (txtPorcentaje.Text.Trim() == "")
            {
                errorProvider1.SetError(txtPorcentaje, "Porcentaje de Base: el campo se encuentra vacio\n\n");
            }
            else
            {
                errorProvider1.SetError(txtPorcentaje, new ValidarDatos().validarNaturales("Porcentaje de Base:", txtPorcentaje.Text));
            }

        }

        private void validarLtrsEnvase()
        {
            errorProvider1.SetError(txtLtrsEnvase, new ValidarDatos().validarRealesPositvos("Litros x Envase:", txtLtrsEnvase.Text));
        }


        private void rbtnBase_Click(object sender, EventArgs e)  //captura los click sobre radios button, usado para Agregar Productos.
        {
            if ((estadoDelFormulario == "estAgregar") & (rbtnBase.Enabled))
            {
                if (!(rbtnDisueltos.Checked)) //Si no es un producto disuelto es decir es un producto terminado o base.
                {
                    System.Windows.Forms.Control[] controlesHabilitados = { this.txtCodBarra, this.txtDescripcion, this.txtPrecioCosto, this.txtPrecioVenta, this.txtStockActual, this.txtCantMinima, this.btnAgregar, this.btnProcesar, this.gbTipo };
                    System.Windows.Forms.Control[] controlesDeshabilitados = { this.btnBusCodigo, this.btnBusDescripcion, this.btnEditar, this.btnEliminar, this.txtBase, this.txtPorcentaje, this.txtLtrsEnvase };
                    System.Windows.Forms.Control[] controlesVisibles = { lblErrorDescripcion, lblErrorPCosto, lblErrorPVenta, lblErrorStockActual, lblErrorCantMin };
                    System.Windows.Forms.Control[] controlesInvisibles = { this.lstProductosCodBarra, this.lstProductosDescripcion, this.lstProductosBases, lblErrorPorcentaje, lblErrorLtrsEnv, lblError };

                    habilitarControles(controlesHabilitados);
                    deshabilitarControles(controlesDeshabilitados);
                    visibleControles(controlesVisibles);
                    invisibleControles(controlesInvisibles);

                }
                else
                {
                    System.Windows.Forms.Control[] controlesHabilitados = { this.txtCodBarra, this.txtDescripcion, this.txtPrecioCosto, this.txtPrecioVenta, this.txtStockActual, this.txtCantMinima, this.btnAgregar, this.btnProcesar, this.gbTipo, this.txtBase, this.txtPorcentaje, this.txtLtrsEnvase };
                    System.Windows.Forms.Control[] controlesDeshabilitados = { this.btnBusCodigo, this.btnBusDescripcion, this.btnEditar, this.btnEliminar };
                    System.Windows.Forms.Control[] controlesVisibles = { lblErrorDescripcion, lblErrorPCosto, lblErrorPVenta, lblErrorStockActual, lblErrorCantMin, lblErrorPorcentaje, lblErrorLtrsEnv };
                    System.Windows.Forms.Control[] controlesInvisibles = { this.lstProductosCodBarra, this.lstProductosDescripcion, this.lstProductosBases, lblError };

                    habilitarControles(controlesHabilitados);
                    deshabilitarControles(controlesDeshabilitados);
                    visibleControles(controlesVisibles);
                    invisibleControles(controlesInvisibles);
                }
            }
            
            
        }


        //metodo capturador del boton eliminar. Si el producto terminado y disuelto lo elimina. Si es un producto base, debe eliminar todas los disueltos previos asociados.
        private void btnEliminar_Click(object sender, EventArgs e) 
        {
            DialogResult result = MessageBox.Show("¿Está seguro que desea eliminar el producto seleccionado?", "CONFIRMACION ELIMINACION DE PRODUCTO", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

            if (result == DialogResult.Yes)
            {
                if ((rbtnTerminados.Checked) || (rbtnDisueltos.Checked)) //si es un terminado o disuelto vendido por granel, se elimina directamente.
                {
                    try
                    {
                        productosTa.DeleteQueryProducto(txtDescripcion.Text); //eliminacion física.

                        //Se muestra un mje de confirmación.
                        MessageBox.Show("Producto eliminado con exito!!!", "AVISO", MessageBoxButtons.OK, MessageBoxIcon.Information);

                        this.vaciarTextBox(); //dejamos todos los textBox en blanco.

                        refrescarResgProductos = true; //debemos actualizar el resguardo de producto

                        resguardarProductoActual();

                        estEsperandoOperacion(); //volvemos al estado ideal.

                    }
                    catch (Exception ex)
                    {
                        //Por cualquier otra excepcion se informa el error, en este caso es un error grave.
                        MessageBox.Show("La conexión a la base de datos no fué exitosa.\n\n Comuniquese con su desarrollador para solucionar el problema.\n\n" + ex.Message, "ERROR GRAVE - ACCESO A BASE DE DATO", MessageBoxButtons.OK, MessageBoxIcon.Error);

                        //Si llega a ocurrir algún error grave se cierra el formulario 
                        this.Close();
                    }

                }
                else
                {
                    if (rbtnBase.Checked) //si es un producto base, solo se elimina si no tiene disueltos asociados.
                    {
                        try
                        {
                            productosTa.FillByDisueltosxCodigo(centerQuimDs.Productos, txtCodBarra.Text); //busca todos los productos disueltos de la base de datos que contengan ese código de base.

                            if (centerQuimDs.Productos.Rows.Count == 0) // si la base no tiene disueltos asociados, se borra; sino se informa que debe borrar los disueltos primeros.
                            {
                                productosTa.DeleteQueryProducto(txtDescripcion.Text); //eliminacion física.

                                //Se muestra un mje de confirmación.
                                MessageBox.Show("Producto eliminado con exito!!!", "AVISO", MessageBoxButtons.OK, MessageBoxIcon.Information);

                                this.vaciarTextBox(); //dejamos todos los textBox en blanco.

                                refrescarResgProductos = true; //debemos actualizar el resguardo de producto

                                estEsperandoOperacion(); //volvemos al estado ideal.

                            }
                            else
                            {
                                //Se muestra un mje de confirmación.
                                MessageBox.Show("No se pueden eliminar la base indicada. \n\nExisten disoluciones asociadas a la base que debe eliminar previamente.", "EXISTENCIAS DE PRODUCTOS DISUELTOS", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            }


                        }
                        catch (Exception ex)
                        {
                            //Por cualquier otra excepcion se informa el error, en este caso es un error grave.
                            MessageBox.Show("La conexión a la base de datos no fué exitosa.\n\n Comuniquese con su desarrollador para solucionar el problema.\n\n" + ex.Message, "ERROR GRAVE - ACCESO A BASE DE DATO", MessageBoxButtons.OK, MessageBoxIcon.Error);

                            //Si llega a ocurrir algún error grave se cierra el formulario 
                            this.Close();
                        }

                    }
                }
            }
            
            
        }

        
        

    }
}
